#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Tue Mar 26 09:40:21 2019

@author: jili
"""
from jili.core import load
from jili.tool.state import config
import os,datetime
from jili.data.db import tradecal
from copy import deepcopy
from jili.data.db import getdb_client
from jili.tool.convert import str2datetime
from jili.tool.state import iswindows
# if iswindows:
#     config.mongodb_ip="192.168.10.44"
objinfo_data_path=os.path.abspath(os.path.join(__file__, r"../../../data/objinfos.pkl"))
if os.path.exists(objinfo_data_path):
    objsinfo=load(objinfo_data_path)
else:
    objsinfo={}
class StockInfo:
    def __init__(self):
        self.data={}
    def getinfo(self,obj):
        if self.data:
            db=getdb_client("stock",config.mongodb_ip)
            for i in db["stock_info"].find({}):
                del i["_id"]
                obj =i["obj"]
                self.data[obj]=i
            db.client.close()
        if obj in self.data.keys():
            return self.data[obj]
        else:
            return {}
    def getname(self,obj):
        if obj in self.data.keys():
            return self.data[obj]["name"]
        else:
            return ""
stockinfo=StockInfo()

def getobjinfo(obj):
    #CThostFtdcInstrumentMarginRateField
    #CThostFtdcInstrumentCommissionRateField
    #CThostFtdcInstrumentField
    #CThostFtdcDepthMarketDataField
    if obj in objsinfo.keys():
        return objsinfo[obj]
    else:
        db=getdb_client("db",config.mongodb_ip)
        objinfo={}
        i=db["obj_info"].find_one({"obj":obj})
        if not i:
            pcode=getpcode_byobj(obj)
            i = db["obj_info"].find_one({"ProductID": pcode})
        obj0=i["obj"]
        objinfo["obj"]=obj
        objinfo["marketcode"]=i["ExchangeID"]
        objinfo["ExchangeID"]=i["ExchangeID"]
        objinfo["ProductID"]=i["ProductID"]
        objinfo["PriceTick"]=i["PriceTick"]
        objinfo["size"]=i["VolumeMultiple"]
        objinfo["MaxMarginSideAlgorithm"]=i["MaxMarginSideAlgorithm"]
        i = db["obj_marginrate_ctp"].find_one({"obj":obj0})
        objinfo["LongMarginRatioByMoney"]=i["LongMarginRatioByMoney"]
        objinfo["LongMarginRatioByVolume"]=i["LongMarginRatioByVolume"]
        objinfo["ShortMarginRatioByMoney"]=i["ShortMarginRatioByMoney"]
        objinfo["ShortMarginRatioByVolume"]=i["ShortMarginRatioByVolume"]
        i=db["obj_commissionrate_ctp"].find_one({"obj":obj0})
        objinfo["OpenRatioByMoney"]=i["OpenRatioByMoney"]
        objinfo["OpenRatioByVolume"]=i["OpenRatioByVolume"]
        objinfo["CloseRatioByMoney"]=i["CloseRatioByMoney"]
        objinfo["CloseRatioByVolume"]=i["CloseRatioByVolume"]
        objinfo["CloseTodayRatioByMoney"]=i["CloseTodayRatioByMoney"]
        objinfo["CloseTodayRatioByVolume"]=i["CloseTodayRatioByVolume"]
        objsinfo[obj]=objinfo
        db.client.close()
        return objinfo
def get_size(obj):
    return getobjinfo(obj)["size"]
def calcopenfee_CNY(obj,price):
    objinfo=getobjinfo(obj)
    return objinfo["OpenRatioByMoney"]*price*objinfo["size"]+objinfo["OpenRatioByVolume"]
def calcclosefee_CNY(obj,price):
    objinfo=getobjinfo(obj)
    return objinfo["CloseRatioByMoney"]*price*objinfo["size"]+objinfo["CloseRatioByVolume"]
def calcclosetodayfee_CNY(obj,price):
    objinfo=getobjinfo(obj)
    return objinfo["CloseTodayRatioByMoney"]*price*objinfo["size"]+objinfo["CloseTodayRatioByVolume"]
def calclongmargin_CNY(obj,price):
    objinfo=getobjinfo(obj)
    return objinfo["LongMarginRatioByMoney"]*price*objinfo["size"]+objinfo["LongMarginRatioByVolume"]
def calcshortmargin_CNY(obj,price):
    objinfo=getobjinfo(obj)
    return objinfo["ShortMarginRatioByMoney"]*price*objinfo["size"]+objinfo["ShortMarginRatioByVolume"]
def calclongpl_CNY(obj,price,costprice):
    objinfo=getobjinfo(obj)
    return (price-costprice)*objinfo["size"]
def calcshortpl_CNY(obj,price,costprice):
    objinfo=getobjinfo(obj)
    return (-price+costprice)*objinfo["size"]
def calcopenfee_tick(obj,price):
    objinfo=getobjinfo(obj)
    return objinfo["OpenRatioByMoney"]*price+objinfo["OpenRatioByVolume"]/objinfo["size"]
def calcclosefee_tick(obj,price):
    objinfo=getobjinfo(obj)
    return objinfo["CloseRatioByMoney"]*price+objinfo["CloseRatioByVolume"]/objinfo["size"]
def calcclosetodayfee_tick(obj,price):
    objinfo=getobjinfo(obj)
    return objinfo["CloseTodayRatioByMoney"]*price+objinfo["CloseTodayRatioByVolume"]/objinfo["size"]
def calclongmargin_tick(obj,price):
    objinfo=getobjinfo(obj)
    return objinfo["LongMarginRatioByMoney"]*price+objinfo["LongMarginRatioByVolume"]/objinfo["size"]
def calcshortmargin_tick(obj,price):
    objinfo=getobjinfo(obj)
    return objinfo["ShortMarginRatioByMoney"]*price+objinfo["ShortMarginRatioByVolume"]/objinfo["size"]
def calclongpl_tick(obj,price,costprice):
    return (price-costprice)
def calcshortpl_tick(obj,price,costprice):
    return (-price+costprice)
def calcopenfee_pct(obj,price):
    objinfo=getobjinfo(obj)
    return objinfo["OpenRatioByMoney"]+objinfo["OpenRatioByVolume"]/price/objinfo["size"]
def calcclosefee_pct(obj,price):
    objinfo=getobjinfo(obj)
    return objinfo["CloseRatioByMoney"]+objinfo["CloseRatioByVolume"]/price/objinfo["size"]
def calcclosetodayfee_pct(obj,price):
    objinfo=getobjinfo(obj)
    return objinfo["CloseTodayRatioByMoney"]+objinfo["CloseTodayRatioByVolume"]/price/objinfo["size"]
def calclongmargin_pct(obj,price):
    objinfo=getobjinfo(obj)
    return objinfo["LongMarginRatioByMoney"]+objinfo["LongMarginRatioByVolume"]/price/objinfo["size"]
def calcshortmargin_pct(obj,price):
    objinfo=getobjinfo(obj)
    return objinfo["ShortMarginRatioByMoney"]+objinfo["ShortMarginRatioByVolume"]/price/objinfo["size"]
def calclongpl_pct(obj,price,costprice):
    return (price-costprice)/price
def calcshortpl_pct(obj,price,costprice):
    return (-price+costprice)/price
class ObjMarket:
    def __init__(self, objs=[]):
        self.objs = objs
        self.objmarketcode = {}
        for obj in objs:
            self.getcode(obj)

    def getcode(self, obj):
        db=getdb_client("db",config.mongodb_ip)
        d = db["obj_info"].find_one({"obj": obj})
        if d:
            # self.objmarketcode[obj]=d["maketcode"]
            self.objmarketcode[obj] = d["marketcode"]
        else:
            d = db["obj_info_all"].find_one({"obj": obj})
            if d:
                self.objmarketcode[obj] = d["marketcode"]
            else:
                self.objmarketcode[obj] = "No"
        db.client.close()
        return self.objmarketcode[obj]

    def getmarketcode(self, obj):
        if obj not in self.objs:
            self.getcode(obj)
        return self.objmarketcode[obj]
def getmarketcode(obj):
    pcode=getpcode(obj)
    return getmarketcode_bypcode(pcode)
pcode_info={}
def get_pcode_info():
    db = getdb_client()
    for i in db["obj_productcode_ctp"].find({}):
        del i["_id"]
        # print(i)
        pcode0 = i["ProductID"]
        pcode_info[pcode0] = i
    db.client.close()
def getpcode_info(pcode):
    if pcode not in pcode_info.keys():
        get_pcode_info()
    if pcode  in pcode_info.keys():
        return pcode_info[pcode]
    else:
        return {}
def getmarketcode_bypcode(pcode):
    if pcode not in pcode_info.keys():
        get_pcode_info()
    if pcode  in pcode_info.keys():
        return pcode_info[pcode]["marketcode"]
    else:
        return ""

market_ctp_w=dict(SHFE="SHF",CZCE="CZC",DCE="DCE",CFFEX="CFE",INE="INE")
market_w_ctp=dict(SHF="SHFE",CZC="CZCE",DCE="DCE",CFE="CFFEX",INE="INE")
def getmkcodebywindcode(windcode):
  key = windcode[-3:]
  return market_w_ctp[key]
def getobj(windcode):
    key = windcode[-3:]
    if (key == "SHF" or key == "DCE" or key == "INE"):
        return windcode[:-8].lower() + windcode[-8:-4]
    else:
        return windcode[:-4]
def getpcode(obj0,mkcode=""):
    if len(obj0)>6:
        obj=obj0.split(".")[0]
    else:
        obj=obj0
    if mkcode=="":
        if obj[-4].isdigit():
            n = len(obj) - 4
            return obj[:n]
        else:
            n = len(obj) - 3
            return obj[:n]
    else:
        if mkcode=="CZCE":
            n=len(obj)-3
            return obj[:n]
        else:
            n=len(obj)-4
            return obj[:n]
class NightCode:
    def __init__(self):
        self.objs={}
        self.nightcode=[]

    def isnighttrade(self,obj,ip=None):
        if ip is None:
            ip=config.mongodb_ip
        db=getdb_client(ip=ip)
        for i in db["obj_activecode_night"].find({},{"obj":1}):
            pcode=getpcode(i["obj"])
            self.nightcode.append(pcode)
        db.client.close()
        pcode=getpcode(obj)
        if pcode in self.nightcode:
            return True
        else:
            return False
nightCode=NightCode()
def isnighttrade(obj):
    return nightCode.isnighttrade(obj)
master_date={}
def getdate_masterobj(obj):
    if obj not in master_date.keys():
        from jili.data.db import getdb_client
        db = getdb_client()
        l=[]
        for i in db["future_master_k1d"].find({"trade_obj":obj}, {"timekey": 1, "trade_obj": 1}).sort([("timekey",1)]):
            t = i["timekey"]
            l.append(t)
        master_date[obj]=l
    l=master_date[obj]
    return l[0],l[-1]
master_data={}
def getobj_masterdate(date,pcode):
    date=str2datetime(date)
    date = datetime.datetime(date.year, date.month, date.day)
    year=date.year
    find={}
    if pcode not in master_data.keys():
        start_date=datetime.datetime(year,1,1)
        end_date=datetime.datetime(year,12,31)
        find={"pcode":pcode,"timekey":{"$gte":start_date,"$lte":end_date}}
    else:
        if year not in master_data[pcode].keys():
            start_date = datetime.datetime(year, 1, 1)
            end_date = datetime.datetime(year, 12, 31)
            find = {"pcode": pcode, "timekey": {"$gte": start_date, "$lte": end_date}}

    if find:
        from jili.data.db import getdb_client
        db = getdb_client()
        if pcode not in master_data.keys():
            master_data[pcode]={}
        if year not in master_data[pcode].keys():
            master_data[pcode][year]={}
        for i in db["future_master_k1d"].find(find,{"timekey":1,"trade_obj":1}):
            t=i["timekey"]
            master_data[pcode][year][t]=i["trade_obj"]
    if date in master_data[pcode][year].keys():
        return master_data[pcode][year][date]
    else:
        return ""
number = []
for i in list(range(10)):
    number.append(str(i))
def getpcode_byobj(obj):
    pcode=""
    for i in obj:
        if i not in number:
            pcode=pcode+i
        else:
            break
    # obj0=obj
    # if len(obj)>6:#仿真，或是期权
    #     if len(obj)<=8:#仿真
    #         obj0=obj[:-2]
    #     else:
    #         obj0=obj.replace("-","").split("C")[0].split("P")[0]
    # if obj0[-4] in number:
    #     pcode = obj0[:-4]
    # else:
    #     pcode = obj0[:-3]
    return pcode
_pcode_tradetime={}
def gettradetime_byobj(obj):
    pcode=getpcode_byobj(obj)
    return gettradetime_bypcode(pcode)
class obj_trade():
    def __init__(self,obj,delta=3):
        self.delta=delta
        self.endtimes = []
        self.timeset = gettradetime_byobj(obj)
        self.tradetime = self.timeset["tradetime"]
        self.stoptime = self.timeset["stoptime"]
        self.isnight = False
        if self.timeset["satrtnight"]:
            self.isnight = True
        for i in self.timeset["tradetime"]:
            self.endtimes.append(i[1])
        self.data_trade_datetime={}
        self.data_stop_datetime={}
        self.data_end_datetime={}
    def gettrade_datetime(self,timekey):
        hour0 = timekey.hour
        if hour0 >= 18:  # 夜盘
            day = tradecal.getnexttradeday(timekey)
        else:
            day = tradecal.gettradeday(timekey)
        if day in self.data_trade_datetime.keys():
            return self.data_trade_datetime[day]
        else:
            if hour0>=18:#夜盘
                day0=timekey
                day1=day0+datetime.timedelta(days=1)
            else:
                day0 = tradecal.getpretradeday(timekey)
                day1 = day0 + datetime.timedelta(days=1)
            if self.isnight:
                havenight = tradecal.istradeday(day0)
            else:
                havenight=False

            if havenight:
                if self.timeset["satrtnight"] is not None and timekey<self.timeset["satrtnight"]:
                    d = [[datetime.datetime(day.year, day.month, day.day, 9, 0),
                          datetime.datetime(day.year, day.month, day.day, 10, 15)],
                         [datetime.datetime(day.year, day.month, day.day, 10, 30),
                          datetime.datetime(day.year, day.month, day.day, 11, 30)],
                         [datetime.datetime(day.year, day.month, day.day, 13, 30),
                          datetime.datetime(day.year, day.month, day.day, 15, 0)]]
                else:
                    d = []
                    for i in self.tradetime:
                        t=[]
                        for j in i:
                            hour1=j.hour
                            if hour1>=18:
                                t.append(datetime.datetime(day0.year, day0.month, day0.day, hour1, j.minute))
                            elif hour1<=3:
                                t.append(datetime.datetime(day1.year, day1.month, day1.day, hour1, j.minute))
                            else:
                                t.append(datetime.datetime(day.year,day.month,day.day,hour1, j.minute))
                        d.append(t)
            else:
                d= [[datetime.datetime(day.year,day.month,day.day,9, 0), datetime.datetime(day.year,day.month,day.day,10, 15)],
                        [datetime.datetime(day.year,day.month,day.day,10, 30), datetime.datetime(day.year,day.month,day.day,11, 30)],
                        [datetime.datetime(day.year,day.month,day.day,13, 30), datetime.datetime(day.year,day.month,day.day,15, 0)]]
            self.data_trade_datetime[day]=d
            return d
    def getend_datetime(self,timekey,havenight=None):
        if havenight is None:
            havenight=self.isnight
        if havenight:
            if self.timeset["satrtnight"]:
                if timekey>=self.timeset["satrtnight"]:
                    return self.endtimes
                else:
                    return [datetime.time(10,15,0),datetime.time(11,30,0),datetime.time(15,0,0)]
            else:
                return self.endtimes
        else:
            return [datetime.time(10, 15, 0), datetime.time(11, 30, 0), datetime.time(15, 0, 0)]
    def getstop_datetime(self,timekey,havenight=None):
        if havenight is None:
            havenight=self.isnight
        if havenight:
            if self.timeset["satrtnight"]:
                if timekey>=self.timeset["satrtnight"]:
                    return self.stoptime
                else:
                    return [[datetime.time(10,15,0),datetime.time(15,0,0)],
                    [datetime.time(11, 30, 0), datetime.time(13, 30, 0)],
                    [datetime.time(15,0,0),datetime.time(9,0,0)]]
            else:
                return self.stoptime
        else:
            return [[datetime.time(10, 15, 0), datetime.time(15, 0, 0)],
                    [datetime.time(11, 30, 0), datetime.time(13, 30, 0)],
                    [datetime.time(15, 0, 0), datetime.time(9, 0, 0)]]
    def gettradetime(self,timekey,havenight=None):
        if havenight is None:
            if self.isnight:
                hour0=timekey.hour
                if hour0>18:#夜盘
                    havenight=tradecal.istradeday(timekey)
                elif hour0<=3:#周六夜盘
                    timekey0=timekey-datetime.timedelta(days=1)
                    havenight = tradecal.istradeday(timekey0)
                else:
                    timekey0 = tradecal.getpretradeday(timekey)
                    havenight = tradecal.istradeday(timekey0)
            else:
                havenight=self.isnight
        if havenight:
            if self.timeset["satrtnight"]:
                if timekey>=self.timeset["satrtnight"]:
                    return self.tradetime
                else:
                    return [[datetime.time(9,0,0),datetime.time(10,15,0)],
                    [datetime.time(10,30,0),datetime.time(11,30,0)],
                    [datetime.time(13,30,0),datetime.time(15,0,0)]]
            else:
                return self.tradetime
        else:
            return [[datetime.time(9, 0, 0), datetime.time(10, 15, 0)],
                    [datetime.time(10, 30, 0), datetime.time(11, 30, 0)],
                    [datetime.time(13, 30, 0), datetime.time(15, 0, 0)]]
    def getendtime(self,timekey,havenight=None):
        if havenight is None:
            havenight=self.isnight
        if havenight:
            if self.timeset["satrtnight"]:
                if timekey>=self.timeset["satrtnight"]:
                    return self.endtimes
                else:
                    return [datetime.time(10,15,0),datetime.time(11,30,0),datetime.time(15,0,0)]
            else:
                return self.endtimes
        else:
            return [datetime.time(10, 15, 0), datetime.time(11, 30, 0), datetime.time(15, 0, 0)]
    def getstoptime(self,timekey,havenight=None):
        if havenight is None:
            havenight=self.isnight
        if havenight:
            if self.timeset["satrtnight"]:
                if timekey>=self.timeset["satrtnight"]:
                    return self.stoptime
                else:
                    return [[datetime.time(10,15,0),datetime.time(15,0,0)],
                    [datetime.time(11, 30, 0), datetime.time(13, 30, 0)],
                    [datetime.time(15,0,0),datetime.time(9,0,0)]]
            else:
                return self.stoptime
        else:
            return [[datetime.time(10, 15, 0), datetime.time(15, 0, 0)],
                    [datetime.time(11, 30, 0), datetime.time(13, 30, 0)],
                    [datetime.time(15, 0, 0), datetime.time(9, 0, 0)]]
    def istradetime(self,a):
        t = a.time()
        test = False
        zone=self.gettradetime(a)
        if self.isnight:
            if not tradecal.istradenight(a):
                zone=self.gettradetime(a,False)
        for i in zone:
            if i[0] > i[1]:
                test = (t >= i[0]) or (t < i[1])
            else:
                test = (t >= i[0]) and (t < i[1])
            if test:
                break
        return test
    def is_close(self,t):
        rst=False
        if self.isnight:
            overtype=0
        else:
            overtype = 1
        tt=t+datetime.timedelta(minutes=self.delta)
        if tt.hour>=15:
            if not tradecal.istradenight(t):
                t1=tradecal.getnexttradeday(t)
                t0=t1-datetime.datetime(t.year,t.month,t.day)
                if t0.days==1:
                    overtype=1
                elif t0.days>3:
                    overtype = 3
                else:
                    overtype = 2
            rst=True
        return rst,overtype
    def isovernight(self,t):
        if self.isnight:
            if t.hour >= 9 and t.hour <= 15:#日盘数据
                return self.is_close(t)
            else:#夜盘数据
                rst = False
                overtype = 1
                tt = t + datetime.timedelta(minutes=self.delta)
                if tt.time() >= self.tradetime[0][1]:
                    t1 = tradecal.getnexttradeday(t)
                    t0 = t1 - datetime.datetime(t.year, t.month, t.day)
                    if t0.days > 3:
                        overtype = 3
                    elif t0.days>2:
                        overtype = 2
                    else:
                        overtype=1
                    rst = True
                return rst, overtype
        else:
            return self.is_close(t)
from jili.tool.state import data_path
def gettradetime_bypcode(pcode,ip=None):
    if pcode not in _pcode_tradetime.keys():
        tt=load(os.path.join(data_path,"info_future_tradetime.pkl"))
        if tt:
            for p,t in tt.items():
                #t=deepcopy(p)
                t["tradetime"] = []
                for i in t["tradetimes"]:
                    tt = (
                    datetime.datetime.strptime(i[0], "%H:%M").time(), datetime.datetime.strptime(i[1], "%H:%M").time())
                    t["tradetime"].append(tt)
                t["stoptime"] = []
                for i in t["stoptimes"]:
                    tt = (
                        datetime.datetime.strptime(i[0], "%H:%M").time(),
                        datetime.datetime.strptime(i[1], "%H:%M").time())
                    t["stoptime"].append(tt)
                _pcode_tradetime[p]=t
        else:
            if ip   is None:
                ip = config.mongodb_ip
            db = getdb_client(ip=ip)
            t = db["info_future_tradetime"].find_one({"pcode": pcode},{"tradetimes":1,"satrtnight":1,"stoptimes":1})
            t["tradetime"]=[]
            for i in t["tradetimes"]:
                tt=(datetime.datetime.strptime(i[0],"%H:%M").time(),datetime.datetime.strptime(i[1],"%H:%M").time())
                t["tradetime"].append(tt)
            t["stoptime"] = []
            for i in t["stoptimes"]:
                tt = (
                datetime.datetime.strptime(i[0], "%H:%M").time(), datetime.datetime.strptime(i[1], "%H:%M").time())
                t["stoptime"].append(tt)
            _pcode_tradetime[pcode]=t
    return _pcode_tradetime[pcode]